/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo.initcolumnsstragety;

import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.ForeignKeyConstraintType;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.DataTypeInterfaceGeneratorContext;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo.InitColumnsGenerator;
import com.inspur.edp.cef.spi.entity.AssociationEnableState;
import com.inspur.edp.cef.spi.entity.AssociationInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleAssoUdtPropertyInfo;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import org.eclipse.jdt.core.dom.*;

public final class AddSimpleAssoUdtColumnStragety extends AddAssociationColumnStategory {

  private final SimpleDataTypeDef udt;

  public AddSimpleAssoUdtColumnStragety(Block block,
      IGspCommonDataType commonDataType,
      IGspCommonField field, AST ast,
      DataTypeInterfaceGeneratorContext parentContext, SimpleDataTypeDef udt,
      ExtendAddPropertyInfoProcessor extendAddPropertyInfoProcessor) {
    super(block, commonDataType, field, ast, parentContext, extendAddPropertyInfoProcessor);
    this.udt = udt;
  }

  @Override
  protected void addSimpleAddStatement(MethodInvocation methodInvocation) {
    addRequiredArgStatement(methodInvocation);
    addEnableRtrimStatement(methodInvocation);
//    addUdtConfigStatement(methodInvocation);
    addAssoInfoStatement(methodInvocation);
  }

  @Override
  protected void addComplexAddStatement(MethodInvocation methodInvocation) {
    addDisplayValueKeyStatement(methodInvocation);
    addRequiredArgStatement(methodInvocation);
    addEnableRtrimStatement(methodInvocation);
    addLengthStatement(methodInvocation);
    addDefaultNullStatment(methodInvocation);
//    addUdtConfigStatement(methodInvocation);
//    addEnableStdTimeFormatStatement(methodInvocation);
    addAssoInfoStatement(methodInvocation);
  }

  protected final void addRefColumnsStatements(GspAssociation association, String varName) {
    for (IGspCommonField refEle : association.getRefElementCollection()) {
      MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName,
          field instanceof IGspCommonElement && field.getIsUdt() && !refEle.getIsFromAssoUdt()
              ? "addEnrichedRefProperty" : "addRefProperty");
      addRefPropertyNameArgs(refEle, invocation);
      addRefedUdtPropertyNameArgs(refEle,invocation);
      addRefedPropertyNameArgs(refEle,invocation);
      block.statements().add(ast.newExpressionStatement(invocation));
    }
  }

  protected void addRefedUdtPropertyNameArgs(IGspCommonField refEle, MethodInvocation invocation) {

    String refElementLabel ="";
    for(IGspCommonField commonField:udt.getChildAssociations().get(0).getRefElementCollection())
    {
      if(refEle.getRefElementId().equals(commonField.getRefElementId()))
        refElementLabel= commonField.getLabelID();
    }
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(refElementLabel);
    invocation.arguments().add(stringLiteral);
  }

  private void addEnableStdTimeFormatStatement(MethodInvocation methodInvocation) {
    BooleanLiteral booleanLiteral = ast.newBooleanLiteral(parentContext.getApiGenContext().getCefGenContext().getEnableStdDateTime());
    methodInvocation.arguments().add(booleanLiteral);
  }

  private void addUdtConfigStatement(MethodInvocation methodInvocation) {
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(udt.getUdtType());
    methodInvocation.arguments().add(stringLiteral);
  }

  @Override
  protected void beforeAddMethodInvocation() {
      GspCommonModel refModel = parentContext.getApiGenContext().getCefGenContext().getMetadataContent("", udt.getChildAssociations().get(0).getRefModelID());
    AssociationEnableState state =
        field.getChildAssociations().getItem(0).getForeignKeyConstraintType() == ForeignKeyConstraintType.Forbid
            ? AssociationEnableState.Disabled
            : AssociationEnableState.Enabled;
      block.statements().add(createUdtInfoStatement(udt,"objectType"+field.getLabelID(),
          SimpleAssoUdtPropertyInfo.class,refModel,state));
    addRefColumnsStatements(field.getChildAssociations().getItem(0),"objectType"+field.getLabelID());
    addSetEnrichAssoTypeStatements(field,block);
    addSetAssoTypeStatements(field,block);
  }

  private void  addSetAssoTypeStatements(IGspCommonField field,Block block) {
    if (field.containRefElementNotFromAssoUdt() == false)
      return;

    String assoType = parentContext.getApiGenContext().getCefGenContext().getEntityGenContext().getElementAssociationTypes().get(field.getID()).getFullName();
    MethodInvocation setAssoTypeinvocation = ast.newMethodInvocation();
    setAssoTypeinvocation.setName(ast.newSimpleName("setAssoType"));
//    ExpressionUtils.getMethodInvocation(ast, assoPropName, "setAssoType");

        MethodInvocation methodInvocationGetAssoInfo = ast.newMethodInvocation();
   methodInvocationGetAssoInfo.setName(ast.newSimpleName("getAssoInfo"));
    methodInvocationGetAssoInfo.setExpression(ast.newSimpleName("objectType"+field.getLabelID()));
    setAssoTypeinvocation.setExpression(methodInvocationGetAssoInfo);


    TypeLiteral typeLiteral = ast.newTypeLiteral();
    typeLiteral.setType(ast.newSimpleType(ast.newName(assoType)));
    setAssoTypeinvocation.arguments().add(typeLiteral);
    block.statements().add(ast.newExpressionStatement(setAssoTypeinvocation));

  }

  //objectTypesalesOrg.getAssoInfo().setAssoType(super.creteClass("com.inspur.gs.scm.sd.sonew0924.salesordernew0928.core.SalesOrderNew0928_SalesOrderNew0928DatasalesOrg"));
  private void addSetEnrichAssoTypeStatements(IGspCommonField field, Block block) {
    boolean containsEnrichedRef = false;
    for (IGspCommonField refEle : field.getChildAssociations().getItem(0).getRefElementCollection())
    {
      if(field instanceof IGspCommonElement && field.getIsUdt() && !refEle.getIsFromAssoUdt())
        containsEnrichedRef=true;
    }
    if(containsEnrichedRef==false)
      return;
    MethodInvocation methodInvocation=ast.newMethodInvocation();
    methodInvocation.setName(ast.newSimpleName("setEnrichedAssType"));

//    MethodInvocation methodInvocationGetAssoInfo = ast.newMethodInvocation();
//    methodInvocationGetAssoInfo.setName(ast.newSimpleName("getAssoInfo"));
      methodInvocation.setExpression(ast.newSimpleName("objectType"+field.getLabelID()));
//    methodInvocation.setExpression(methodInvocationGetAssoInfo);

    MethodInvocation methodInvocationCreateClass = ast.newMethodInvocation();
    methodInvocationCreateClass.setName(ast.newSimpleName("createClass"));
    StringLiteral stringLiteral=ast.newStringLiteral();


    String enrichedClassName ="";
      String code = parentContext.getApiGenContext().getCefGenContext().getMetadata().getHeader()
              .getCode();
//      if (field.getBelongObject() instanceof IGspCommonObject  && ((IGspCommonObject)field.getBelongObject()).getParentObject()==null) {
//        enrichedClassName= code + "Data"+field.getLabelID();
//      }
//      else
        enrichedClassName = code + "_" + field.getBelongObject().getCode() + "Data"+field.getLabelID();

String genClassPath=field.getBelongObject().getGeneratedEntityClassInfo().getClassNamespace();
    stringLiteral.setLiteralValue(genClassPath.substring(0,genClassPath.length()-7)+".core."+enrichedClassName);
    methodInvocationCreateClass.arguments().add(stringLiteral);

    methodInvocation.arguments().add(methodInvocationCreateClass);
    block.statements().add(ast.newExpressionStatement(methodInvocation));
  }

  private Statement createUdtInfoStatement(UnifiedDataTypeDef udtDef, String varName, Class type,
      GspCommonModel refModel, AssociationEnableState state) {
    TypeInfo info = new TypeInfo(type);
    StringLiteral stringLiteral = ast.newStringLiteral();
    stringLiteral.setLiteralValue(udtDef.getUdtType());
    BooleanLiteral booleanLiteral = ast.newBooleanLiteral(parentContext.getApiGenContext().getCefGenContext().getEnableStdDateTime());

    VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
    fragment.setName(ast.newSimpleName(varName));
    ClassInstanceCreation creation = ast.newClassInstanceCreation();
    creation.setType(info.getType(ast, parentContext.getApiGenContext()));
    creation.arguments().add(stringLiteral);
    creation.arguments().add(booleanLiteral);

    parentContext.getApiGenContext(). addImport(AssociationEnableState.class.getTypeName());
    QualifiedName enableStateValue =
        ast.newQualifiedName(
            ast.newName("AssociationEnableState"),
            ast.newSimpleName(state.toString()));
    creation.arguments().add(enableStateValue);

    AssociationInfo ass = InitColumnsGenerator
        . getAssociationInfo(this.parentContext, field.getChildAssociations().getItem(0), commonDataType);
    StringLiteral targetColumnLiteral=ast.newStringLiteral();
    targetColumnLiteral.setLiteralValue(ass.getPrivateTargetColumn());
    creation.arguments().add(targetColumnLiteral);

    fragment.setInitializer(creation);
    VariableDeclarationStatement statement = ast.newVariableDeclarationStatement(fragment);

    statement.setType(
        info.getType(ast, parentContext.getApiGenContext()));
    return statement;
  }

  @Override
  protected final String getMethodName() {
    return "addAssoUdtPropertyInfo";
  }
}
